using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Diagnostics;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.SqlExpressions;
using Microsoft.EntityFrameworkCore.Storage;

namespace Microsoft.EntityFrameworkCore.Dm.Query.Internal;

public class DmObjectToStringTranslator : IMethodCallTranslator
{
	private const int DefaultLength = 100;

	private static readonly Dictionary<Type, string> _typeMapping = new Dictionary<Type, string>
	{
		{
			typeof(int),
			"VARCHAR(11)"
		},
		{
			typeof(long),
			"VARCHAR(20)"
		},
		{
			typeof(DateTime),
			$"VARCHAR({100})"
		},
		{
			typeof(Guid),
			"CHAR(36)"
		},
		{
			typeof(byte),
			"VARCHAR(3)"
		},
		{
			typeof(byte[]),
			$"VARCHAR({100})"
		},
		{
			typeof(double),
			$"VARCHAR({100})"
		},
		{
			typeof(DateTimeOffset),
			$"VARCHAR({100})"
		},
		{
			typeof(char),
			"VARCHAR(1)"
		},
		{
			typeof(short),
			"VARCHAR(6)"
		},
		{
			typeof(float),
			$"VARCHAR({100})"
		},
		{
			typeof(decimal),
			$"VARCHAR({100})"
		},
		{
			typeof(TimeSpan),
			$"VARCHAR({100})"
		},
		{
			typeof(uint),
			"VARCHAR(10)"
		},
		{
			typeof(ushort),
			"VARCHAR(5)"
		},
		{
			typeof(ulong),
			"VARCHAR(19)"
		},
		{
			typeof(sbyte),
			"VARCHAR(4)"
		}
	};

	private readonly ISqlExpressionFactory _sqlExpressionFactory;

	public DmObjectToStringTranslator(ISqlExpressionFactory sqlExpressionFactory)
	{
		_sqlExpressionFactory = sqlExpressionFactory;
	}

	public virtual SqlExpression Translate(SqlExpression instance, MethodInfo method, IReadOnlyList<SqlExpression> arguments, IDiagnosticsLogger<DbLoggerCategory.Query> logger)
	{
		if (!(method.Name == "ToString") || arguments.Count != 0 || instance == null || !_typeMapping.TryGetValue(((Expression)(object)instance).Type.UnwrapNullableType(), out string value))
		{
			return null;
		}
		return (SqlExpression)(object)_sqlExpressionFactory.Function("CONVERT", (IEnumerable<SqlExpression>)(object)new SqlExpression[2]
		{
			(SqlExpression)_sqlExpressionFactory.Fragment(value),
			instance
		}, true, (IEnumerable<bool>)new bool[2] { false, true }, typeof(string), (RelationalTypeMapping)null);
	}
}
